package com.dhemery.mack.model.tests;

import static org.junit.Assert.assertEquals;

import java.util.ArrayList;
import java.util.List;

import org.junit.Test;

import com.dhemery.mack.model.Item;
import com.dhemery.mack.model.ItemChangeListener;

public class ItemChangeNotificationTests {

	@Test
	public void doesNotNotifyListenerOnInitialName() {
		FakeItemChangeListener listener = new FakeItemChangeListener();
		Item.subscribeToNameChange(listener);

		new Item("name");

		assertEquals(0, listener.getNameChangeNotificationCount());
	}

	@Test
	public void notifiesListenerOnNameChange() {
		FakeItemChangeListener listener = new FakeItemChangeListener();
		Item.subscribeToNameChange(listener);
		Item item = new Item("initial name");

		item.setName("new name");

		assertEquals(1, listener.getNameChangeNotificationCount());
		assertEquals(item, listener.getNameChangeNotificationItem(1));
	}

	@Test
	public void notifiesListenerOnEachNameChange() {
		FakeItemChangeListener listener = new FakeItemChangeListener();
		Item.subscribeToNameChange(listener);
		Item item1 = new Item("initial name");
		Item item2 = new Item("initial name");

		item1.setName("new name");
		item2.setName("new name");
		item1.setName("another new name");

		assertEquals(3, listener.getNameChangeNotificationCount());
		assertEquals(item1, listener.getNameChangeNotificationItem(1));
		assertEquals(item2, listener.getNameChangeNotificationItem(2));
		assertEquals(item1, listener.getNameChangeNotificationItem(3));
	}

	@Test
	public void notifiesEachListenerOnNameChange() {
		FakeItemChangeListener listener1 = new FakeItemChangeListener();
		FakeItemChangeListener listener2 = new FakeItemChangeListener();
		FakeItemChangeListener listener3 = new FakeItemChangeListener();
		Item.subscribeToNameChange(listener1);
		Item.subscribeToNameChange(listener2);
		Item.subscribeToNameChange(listener3);
		Item item = new Item("initial name");

		item.setName("new name");

		assertEquals(1, listener1.getNameChangeNotificationCount());
		assertEquals(1, listener2.getNameChangeNotificationCount());
		assertEquals(1, listener3.getNameChangeNotificationCount());
	}

	@Test
	public void doesNotNotifyIfNewNameEqualsCurrentName() {
		FakeItemChangeListener listener = new FakeItemChangeListener();
		Item.subscribeToNameChange(listener);
		String itemName = "the name";
		Item item = new Item(itemName);

		item.setName(itemName);

		assertEquals(0, listener.getNameChangeNotificationCount());
	}

	class FakeItemChangeListener implements ItemChangeListener {
		private List<Item> nameChangeNotificationItems = new ArrayList<Item>();

		public int getNameChangeNotificationCount() {
			return nameChangeNotificationItems.size();
		}

		public Item getNameChangeNotificationItem(int n) {
			return nameChangeNotificationItems.get(n-1);
		}

		public void nameChanged(Item item) {
			nameChangeNotificationItems.add(item);
		}
	}
}
